package com.dong.c07_netty_simple;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.util.CharsetUtil;

import java.util.concurrent.TimeUnit;


/**
 * <h1></h1>
 * 说明:
 * 1. 我们自定义一个Handler, 需要继承netty规定好的HandlerAdapter{@link ChannelInboundHandlerAdapter}
 * 2. 这时我们自定义一个Handler,才能是Handler
 *
 * pipeline 本质是一个双向链表
 * @author : dzj
 * @create: 2020-03-19 20:36
 */
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    //读取数据时机

    /**
     *
     * @param ctx
     * @param msg
     * @throws Exception
     *   ChannelHandlerContext ctx: 上下文对象, 含有管道pipeline, 通道channel, 地址
     *   Object msg: 客户端发送的数据
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        //   doReadChannelSimple(ctx,msg);

        // 1. 自定义普通任务
        doReadChannelWithComplexTask(ctx,msg);
        //2. 自定义定时任务
     //   doReadChannelSchedule(ctx,msg);
    }


    /**
     *  简单的读取
     * @param ctx
     * @param msg
     */
    private void doReadChannelSimple(ChannelHandlerContext ctx, Object msg) {
        System.out.println();
        System.out.println(">>>>>>>>>>>>>>>>");
        System.out.println("服务器读取线程"+Thread.currentThread().getName());
        System.out.println("server ctx = "+ctx);
        System.out.println("看看channel 和 pipeline 的关系, channel : " + ctx.channel()+", pipeline: "+ctx.pipeline());
        ByteBuf buf = (ByteBuf) msg;
        System.out.println("客户端发送的消息: "+buf.toString(CharsetUtil.UTF_8));
        System.out.println("客户端地址: "+ctx.channel().remoteAddress());
    }


    /**
     * 这里有个非常耗时的业务  希望异步执行 -->提交到该channel对应的NIOEventLoop 的taskQueue
     * 解决方案1 , 用户程序自定义的普通任务   , 两个是由同一个线程完成
     *  用他自己的线程池, 也就是boss的线程池
     *   这个任务提交到 taskQueue
     * @param ctx
     * @param msg
     */
    private void doReadChannelWithComplexTask(ChannelHandlerContext ctx, Object msg) {
        ctx.channel().eventLoop().execute(() -> {
            try {
                Thread.sleep(10*1000);
                ctx.writeAndFlush(Unpooled.copiedBuffer("hello ,客户端 , (￢_￢) 喵2 ",CharsetUtil.UTF_8));

            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("发生异常"+e.getMessage());
            }
        });
        ctx.channel().eventLoop().execute(() -> {
            try {
                Thread.sleep(5*1000);
                ctx.writeAndFlush(Unpooled.copiedBuffer("hello ,客户端 , (￢_￢) 喵3 ",CharsetUtil.UTF_8));

            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("发生异常"+e.getMessage());
            }
        });
    }

    /**
     * 方式2  用户自定义定时任务   >  该任务提交到scheduleTaskQueue中
     * @param ctx
     * @param msg
     */
    private void doReadChannelSchedule(ChannelHandlerContext ctx, Object msg) {
        ctx.channel().eventLoop().schedule(()-> {
            try {
                Thread.sleep(5000);
                ctx.writeAndFlush(Unpooled.copiedBuffer("hello ,客户端 , (￢_￢) 喵4 ",CharsetUtil.UTF_8));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },10, TimeUnit.SECONDS);
    }

    //数据读取完毕
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        /**
         * 数据写出 并同时刷新缓冲区
         */
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello ,客户端 , (￢_￢) , 你的消息 我读完了  [ channelReadComplete ] ",CharsetUtil.UTF_8));
       // super.channelReadComplete(ctx);
    }
    /**
     *  发生异常时 , 需要关闭通道
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.channel().close();
        ctx.close();
    }
}
